package com.jchen.system.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.TrackHits;
import com.github.pagehelper.PageInfo;
import com.jchen.elasticsearch.dto.SysUserEsQueryReqDto;
import com.jchen.elasticsearch.util.EsPageUtil;
import com.jchen.elasticsearch.vo.SysUserEsRes;
import com.jchen.system.config.SearchIndexConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description
 * @Author jchen
 * @Date 2023/12/22 10:05
 */
@Service
public class SysUserSearchService {

    @Resource
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private SearchIndexConfig indexConfig;

    public <T> PageInfo<T> search(Integer pageNum, Integer pageSize, SysUserEsQueryReqDto sysUserEsQueryReqDto, Class<T> cls) throws IOException {
        return search(indexConfig.getUser(), pageNum, pageSize, sysUserEsQueryReqDto, cls);
    }

    /**
     * 分页检索实有人口
     * @param index 索引名称，必传
     * @param pageNum 当前页
     * @param pageSize 页大小
     * @param sysUserEsQueryReqDto 查询条件
     * @param cls 需转换的对象，采用属性复制
     * @param <T>
     * @return
     * @throws IOException
     */
    public <T> PageInfo<T> search(String index, Integer pageNum, Integer pageSize, SysUserEsQueryReqDto sysUserEsQueryReqDto, Class<T> cls) throws IOException {
        PageInfo<SysUserEsRes> esSearchResPageInfo = search(index, pageNum, pageSize, sysUserEsQueryReqDto);

        PageInfo<T> pageInfo = new PageInfo<>();
        BeanUtil.copyProperties(esSearchResPageInfo, pageInfo, "list");
        List<T> list = new ArrayList<>();
        esSearchResPageInfo.getList().forEach(esSearchRes -> {
            T obj = ReflectUtil.newInstance(cls);
            BeanUtil.copyProperties(esSearchRes, obj);
            list.add(obj);
        });
        pageInfo.setList(list);
        return pageInfo;
    }

    public PageInfo<SysUserEsRes> search(String index, Integer pageNum, Integer pageSize, SysUserEsQueryReqDto sysUserEsQueryReqDto) throws IOException {
        SearchResponse<SysUserEsRes> searchResponse = searchReal(index, pageNum, pageSize, sysUserEsQueryReqDto);
        return EsPageUtil.convertToPageInfo(pageNum, pageSize, searchResponse);
    }

    /**
     * 分页
     * @param index
     * @param pageNum
     * @param pageSize
     * @param sysUserEsQueryReqDto
     * @return
     * @throws IOException
     */
    public SearchResponse<SysUserEsRes> searchReal(String index, Integer pageNum, Integer pageSize, SysUserEsQueryReqDto sysUserEsQueryReqDto) throws IOException {
        // 参数校验
        Assert.notBlank(index, "未配置Elasticsearch人口查询索引");
        EsPageUtil.checkMaxResult(pageNum, pageSize);

        // 构造查询条件
        Query query = sysUserEsQueryReqDto.buildQuery();
        // 查询请求体
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder()
                .index(index).query(query)
                // 计算真实总记录数
                .trackTotalHits(new TrackHits.Builder().enabled(true).build());
        if (null != pageNum) {
            int size = null == pageSize ? 10 : pageSize;
            searchRequestBuilder.from((pageNum - 1) * size);
        }
        if (null != pageSize) {
            searchRequestBuilder.size(pageSize);
        }
        return elasticsearchClient.search(searchRequestBuilder.build(), SysUserEsRes.class);
    }

    //-------------------------------不分页------------------------------------

    public <T> SearchResponse<T> search(SysUserEsQueryReqDto sysUserEsQueryReqDto, Class<T> cls) throws IOException {
        return search(indexConfig.getUser(), sysUserEsQueryReqDto, cls);
    }

    /**
     * @param index 索引名称，必传
     * @param sysUserEsQueryReqDto 查询条件
     * @param cls 需转换的对象，采用属性复制
     * @param <T>
     * @return
     * @throws IOException
     */
    public <T> SearchResponse<T> search(String index, SysUserEsQueryReqDto sysUserEsQueryReqDto, Class<T> cls) throws IOException {
        SearchResponse esSearchResPageInfo = searchReal(index, sysUserEsQueryReqDto);

        return esSearchResPageInfo;
    }

    /**
     * 不分页
     * @param index
     * @param sysUserEsQueryReqDto
     * @return
     * @throws IOException
     */
    public SearchResponse<SysUserEsRes> searchReal(String index, SysUserEsQueryReqDto sysUserEsQueryReqDto) throws IOException {
        // 参数校验
        Assert.notBlank(index, "未配置Elasticsearch人口查询索引");

        // 构造查询条件
        Query query = sysUserEsQueryReqDto.buildQuery();
        // 查询请求体
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder()
                .index(index).query(query)
                // 计算真实总记录数
                .trackTotalHits(new TrackHits.Builder().enabled(true).build());
        return elasticsearchClient.search(searchRequestBuilder.build(), SysUserEsRes.class);
    }
}
